package org.gary.core.factories.impl;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;

import lengreen.core.interfaces.Entity;

import org.apache.commons.dbcp.BasicDataSource;
import org.gary.core.factories.BasicDaoFactory;
import org.gary.core.util.DBUtile;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

import static lengreen.util.BuildQuery.*;

import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Component;

/**
 * basic dao工厂
 * @author lengreen
 *
 * @param <E> 实体类Class
 */
@Component("basicDaoFactory")
public class BasicDaoFactoryImpl<E> implements BasicDaoFactory<E> {
	private HibernateTemplate hibernateTemplate;
	private BasicDataSource dataSource;
	private DBUtile dbUtil;
	
	@Resource
	public void setDbUtil(DBUtile dbUtil) {
		this.dbUtil = dbUtil;
	}
	private String hql;
	private String countQuery;
	private String countQueryHead = "select count(*) from ";

	public void delete(Entity entity) {
		hibernateTemplate.delete(entity);
	}

	public void delete(Class<E> entity, final Object[] ids) {
		setHql("delete from " + entity.getName() + " entity where entity.id in (:ids)");
		hibernateTemplate.execute(new HibernateCallback<E>() {

			public E doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query q = session.createQuery(hql);
				q.setParameterList("ids", ids);
				q.executeUpdate();
				return null;
			}
		});
	}

	public E load(Class<E> entity, int id) {
		return hibernateTemplate.get(entity, id);
	}

	@SuppressWarnings("unchecked")
	public E load(Class<E> entity, int id,Object lang) {
		setHql("from " + entity.getName() + " entity where id="+id+" and visible=true and lang='"+lang+"'");
		E e=hibernateTemplate.execute(new HibernateCallback<E>() {

			@Override
			public E doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query q = session.createQuery(getHql()).setCacheable(true);
				return (E)q.uniqueResult();
			}
		});
		return e;
	}
	@SuppressWarnings("unchecked")
	public E load(Class<E> entity, Object lang) {
		setHql("from " + entity.getName() + " entity where visible=true and lang='"+lang+"'");
		E e=hibernateTemplate.execute(new HibernateCallback<E>() {

			@Override
			public E doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query q = session.createQuery(getHql()).setCacheable(true);
				return (E)q.uniqueResult();
			}
		});
		return e;
	}
	
	@SuppressWarnings("unchecked")
	public List<E> list(Class<E> entity) {
		return hibernateTemplate.find("from " + entity.getName() + " entity where visible=true");
	}
	
	@SuppressWarnings("unchecked")
	public List<E> list(Class<E> entity,final int top,final int page,Object lang,int type) {
		if(type==-1){
			setHql("from " + entity.getName() + " entity where visible=true and lang='"+lang+"' "+buildOrderBy(new Object[] { " entity.id desc " }));
		}else{
			setHql("from " + entity.getName() + " entity where visible=true and lang='"+lang+"' and category_id="+type+" "+buildOrderBy(new Object[] { " entity.id desc " }));
		}		
		List<E> list = hibernateTemplate.executeFind(new HibernateCallback<E>() {

			@Override
			public E doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query q = session.createQuery(hql).setCacheable(true);
				q.setFirstResult((page - 1) * top);
				q.setMaxResults(top);
				return (E)q.list();
			}
		});
		
		return list;
	}
	
	@SuppressWarnings("unchecked")
	public List<E> list(Class<E> entity, String groupBy) {
		return hibernateTemplate.find("from " + entity.getName() + " entity " + buildGroupBy(groupBy));
	}

	@SuppressWarnings("unchecked")
	public List<E> list(Class<E> entity, final int pageNo, final int maxCount,
			Object[] orderBy) {
		setHql("from " + entity.getName() + " entity" + buildOrderBy(orderBy));
		setCountQuery(countQueryHead + entity.getName() + " entity where 1=1");
		List<E> list = hibernateTemplate.executeFind(new HibernateCallback<E>() {

			public E doInHibernate(Session session) throws HibernateException, SQLException {
				Query q = session.createQuery(hql).setCacheable(true);
				q.setFirstResult((pageNo - 1) * maxCount);
				q.setMaxResults(maxCount);
				return (E) q.list();
			}
		});
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<E> list(Class<E> entity, Map<String, Object> where,
			Object[] orderBy) {
		String whereSql = buildWhere(where);
		setHql("from " + entity.getName() + " entity where 1=1 " + whereSql + buildOrderBy(orderBy));
		setCountQuery(countQueryHead + entity.getName() + " entity where 1=1 "
				+ whereSql);
		List<E> list = hibernateTemplate.executeFind(new HibernateCallback<E>() {

			public E doInHibernate(Session session) throws HibernateException, SQLException {
				Query q = session.createQuery(hql).setCacheable(true);
				return (E) q.list();
			}
		});
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<E> list(Class<E> entity, final int pageNo,
			final int maxCount, Map<String, Object> where, Object[] orderBy) {
		String whereSql = buildWhere(where);
		setHql("from " + entity.getName() + " entity where 1=1 " + whereSql + buildOrderBy(orderBy));
		setCountQuery(countQueryHead + entity.getName() + " entity where 1=1 " + whereSql);
		List<E> list = hibernateTemplate.executeFind(new HibernateCallback<E>() {

			public E doInHibernate(Session session) throws HibernateException, SQLException {
				Query q = session.createQuery(hql).setCacheable(true);
				q.setFirstResult((pageNo - 1) * maxCount);
				q.setMaxResults(maxCount);
				return (E) q.list();
			}
		});
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<E> list(Class<E> entity, final int pageNo, final int maxCount,
			Map<String, Object> where, String groupBy, Object[] orderBy) {
		String whereSql = buildWhere(where);
		setHql("from " + entity.getName() + " entity where 1=1 " + whereSql
				+ buildGroupBy(groupBy) + buildOrderBy(orderBy));
		setCountQuery(countQueryHead + entity.getName() + " entity where 1=1 "
				+ whereSql);
		List<E> list = hibernateTemplate.executeFind(new HibernateCallback<E>() {

			public E doInHibernate(Session session) throws HibernateException, SQLException {
				Query q = session.createQuery(hql).setCacheable(true);
				q.setFirstResult((pageNo - 1) * maxCount);
				q.setMaxResults(maxCount);
				return (E) q.list();
			}

		});
		return list;
	}

	public void save(E entity) {
		hibernateTemplate.save(entity);
	}

	public int selectTotalCount(Class<E> entity) {
		if (entity != null) {
			setCountQuery(countQueryHead + entity.getName());
		}
		if (countQuery != null && !"".equals(countQuery)) {
			Object obj = hibernateTemplate.execute(new HibernateCallback<E>() {

				@SuppressWarnings("unchecked")
				public E doInHibernate(Session session)
						throws HibernateException, SQLException {
					Query q = session.createQuery(countQuery)
							.setCacheable(true);
					return (E) q.uniqueResult();
				}
			});
			return new Integer(obj.toString());
		}
		return 0;
	}

	public void update(Entity entity) {
		System.out.println("update in basic dao-->" + entity.getClass());
		hibernateTemplate.update(entity);
	}

	public int[] update(Class<E> entity, final Object[] ids, final boolean visible) {
		setHql("update " + buildNativeTableName(entity)
				+ " set visible = ? where id = ?");
		BatchPreparedStatementSetter bpsSetter = new BatchPreparedStatementSetter() {

			public void setValues(PreparedStatement ps, int i)
					throws SQLException {
				ps.setObject(1, visible);
				ps.setObject(2, ids[i]);
			}

			public int getBatchSize() {
				return ids.length;
			}
		};
		return new JdbcTemplate(dataSource).batchUpdate(hql, bpsSetter);
	}
	
	public int[] updateResume(Class<E> entity, final Object[] ids) {
		setHql("update " + buildNativeTableName(entity)
				+ " set visible = ? where id = ?");
		BatchPreparedStatementSetter bpsSetter = new BatchPreparedStatementSetter() {
			
			public void setValues(PreparedStatement ps, int i)
			throws SQLException {
				ps.setObject(1, true);
				ps.setObject(2, ids[i]);
			}
			
			public int getBatchSize() {
				return ids.length;
			}
		};
		return new JdbcTemplate(dataSource).batchUpdate(hql, bpsSetter);
	}
	
	@Resource
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}

	@Resource
	public void setDataSource(BasicDataSource dataSource) {
		this.dataSource = dataSource;
	}

	public BasicDataSource getDataSource() {
		return dataSource;
	}

	public String getHql() {
		return hql;
	}

	public void setHql(String hql) {
		this.hql = hql;
	}

	public void setCountQuery(String countQuery) {
		this.countQuery = countQuery;
	}

	public String getCountQuery() {
		return countQuery;
	}

	@SuppressWarnings("unchecked")
	@Override
	public E load(Class<E> entity, String name, Object lang) {
		setHql("from " + entity.getName() + " entity where visible=true and lang='"+lang+"' and name='"+name+"'");
		E e=hibernateTemplate.execute(new HibernateCallback<E>() {

			@Override
			public E doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query q = session.createQuery(getHql()).setCacheable(true);
				return (E)q.uniqueResult();
			}
		});
		return e;
	}
	public List<Integer> getId(int id){
		List<Integer> list=new ArrayList<Integer>();
		String sql = "Select id from category where parent_id="+id;
		ResultSet rs = null;
		try {
			rs = dbUtil.execuetQuery(sql, null);
			while (rs.next()) {
				list.add(rs.getInt(1));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			dbUtil.closedAll();
		}
		list.add(id);
		return list;
	}
	public boolean getParentId(int id){
		String sql = "Select parent_id from category where id="+id;
		ResultSet rs = null;
		try {
			rs = dbUtil.execuetQuery(sql, null);
			while (rs.next()) {
				if(rs.getInt(1)==0){
					return false;
				}
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			dbUtil.closedAll();
		}		
		return false;
	}
	@SuppressWarnings("unchecked")
	public List<E> list(Class<E> entity,final int top,final int page,Object lang,List<Integer> type) {		
		String id="";
		int i=0;
		for (Integer integer : type) {
			i++;
			if(i==type.size()){
				id=id+integer;
			}else{
				id=id+integer+" or category_id=";
			}
		}
		setHql("from " + entity.getName() + " entity where visible=true and lang='"+lang+"' and category_id="+id+" "+buildOrderBy(new Object[] { " entity.id desc " }));
		List<E> list = hibernateTemplate.executeFind(new HibernateCallback<E>() {

			@Override
			public E doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query q = session.createQuery(hql).setCacheable(true);
				q.setFirstResult((page - 1) * top);
				q.setMaxResults(top);
				return (E)q.list();
			}
		});
		
		return list;
	}
}
